﻿using System;
using System.IO;
using System.Linq;

using NewModel.Shared.FileSystem;

using NUnit.Framework;

namespace NewModel.UnitTests.Shared.FileSystem
{
	[TestFixture]
	public sealed class TestDirectoryImpl
	{
		DirectoryImpl mUnderTest;
		string mTempDirectory;

		[SetUp]
		public void SetUp()
		{
			mTempDirectory = Path.GetTempFileName();
			File.Delete(mTempDirectory);
			mUnderTest = new DirectoryImpl(mTempDirectory);
		}
		[TearDown]
		public void Dispose()
		{
			if (Directory.Exists(mTempDirectory))
			{
				Directory.Delete(mTempDirectory, true);
				mTempDirectory = null;
			}
		}

		[Test]
		public void Ctor_When_Null_Should_Throw()
		{
			Assert.Throws<ArgumentNullException>(() => new DirectoryImpl(null));
		}

		[Test]
		public void Ctor_Should_Initialize_Properties()
		{
			Assert.That(mUnderTest.FullName, Is.EqualTo(mTempDirectory));
			Assert.That(mUnderTest.Name, Is.EqualTo(Path.GetFileName(mTempDirectory)));
		}

		[Test]
		public void FullName_When_Condition_Should_Work()
		{
			mUnderTest = new DirectoryImpl(@"c:\level1\level2");
			Assert.That(mUnderTest.Parent.FullName, Is.EqualTo(@"c:\level1"));
			Assert.That(mUnderTest.Parent.Parent.FullName, Is.EqualTo(@"c:\"));
			Assert.That(mUnderTest.Parent.Parent.Parent, Is.Null);
		}


		[Test]
		public void CreateDirectory_Should_Work()
		{
			mUnderTest.Create();
			Assert.That(Directory.Exists(mTempDirectory));
		}

		[Test]
		public void CreateDirectory_When_DirectoryExists_Should_Work()
		{
			mUnderTest.Create();
			Assert.DoesNotThrow(() => mUnderTest.Create());
		}

		[Test]
		public void DirectoryExists_Should_Work()
		{
			Assert.That(mUnderTest.Exists, Is.False);
			Directory.CreateDirectory(mTempDirectory);
			Assert.That(mUnderTest.Exists, Is.True);
		}

		[Test]
		public void Clear_Should_Work()
		{
			CreateDirectoryAndSomeFiles();
			mUnderTest.Clear();
			Assert.That(Directory.GetFiles(mTempDirectory).Length, Is.EqualTo(0));
		}

		[Test]
		public void Clear_When_Directory_Not_Exist_Should_Work()
		{
			Assert.Throws<DirectoryNotFoundException>(() => mUnderTest.Clear());
		}

		[Test]
		public void GetAllFiles_Should_Work()
		{
			CreateDirectoryAndSomeFiles();
			Assert.That(mUnderTest.GetFiles().Select(f => f.FullName), Is.EquivalentTo(new[]
				{
					mTempDirectory + @"\temp1", 
					mTempDirectory + @"\temp2a",
					mTempDirectory + @"\dir\temp3", 
					mTempDirectory + @"\dir\temp4a"
				}));
		}

		[Test]
		public void GetFiles_When_Not_Recursive_Should_Work()
		{
			CreateDirectoryAndSomeFiles();
			Assert.That(mUnderTest.GetFiles("*", false).Select(f => f.FullName), Is.EquivalentTo(new[]
				{
					mTempDirectory + @"\temp1", 
					mTempDirectory + @"\temp2a"
				}));
		}

		[Test]
		public void GetFiles_When_Pattern_Should_Work()
		{
			CreateDirectoryAndSomeFiles();
			Assert.That(mUnderTest.GetFiles("*a", true).Select(f => f.FullName), Is.EquivalentTo(new[]
				{
					mTempDirectory + @"\temp2a", 
					mTempDirectory + @"\dir\temp4a"
				}));
		}

		[Test]
		public void GetFiles_When_Invalid_Pattern_Should_Work()
		{
			CreateDirectoryAndSomeFiles();
			Assert.Throws<ArgumentNullException>(() => mUnderTest.GetFiles(null, true));
		}

		[Test]
		public void IsEmpty_WhenEmpty_Should_Return_True()
		{
			Directory.CreateDirectory(mTempDirectory);
			Assert.That(mUnderTest.HasFiles, Is.True);
		}

		[Test]
		public void IsEmpty_WhenNotEmpty_Should_Return_False()
		{
			CreateDirectoryAndSomeFiles();
			Assert.That(mUnderTest.HasFiles, Is.False);
		}

		[Test]
		public void MoveTo_Should_Work()
		{
			CreateDirectoryAndSomeFiles();
			var target = new DirectoryInfo(mTempDirectory + "/../" + Path.GetFileName(mTempDirectory) + "2").FullName;
			Directory.CreateDirectory(target);

			mUnderTest.MoveTo(new DirectoryImpl(target));
			Assert.That(Directory.Exists(target),Is.True);
			Assert.That(Directory.Exists(mTempDirectory),Is.False);

			Directory.Delete(target, true);
		}

		void CreateDirectoryAndSomeFiles()
		{
			Directory.CreateDirectory(mTempDirectory);
			File.Create(mTempDirectory + @"/temp1").Close();
			File.Create(mTempDirectory + @"/temp2a").Close();
			Directory.CreateDirectory(mTempDirectory + "/dir");
			File.Create(mTempDirectory + @"/dir/temp3").Close();
			File.Create(mTempDirectory + @"/dir/temp4a").Close();
		}

		[Test]
		public void GetFile()
		{
			Directory.CreateDirectory(mTempDirectory);
			File.Create(mTempDirectory + "\\blah").Close();
			Assert.That(mUnderTest.GetFile("blah").Exists, Is.True);
		}

		[Test]
		public void GetFile_When_File_Does_Not_Exist()
		{
			Assert.That(mUnderTest.GetFile("missing").FullName, Is.EqualTo(mTempDirectory + "\\missing"));
		}
		#region ' Equality '

		// We do not test those methods 'cause they are autogenerated

		#endregion

	}
}